#!/usr/bin/python
#
# (c) 2006 Travis F Vachon
#
# This software is distributable under the terms of the GNU
# General Public License (GPL) v2, the text of which can be found at
# http://www.gnu.org/copyleft/gpl.html. Installing, importing or otherwise
# using this module constitutes acceptance of the terms of this License.
#
# Disclaimer
# 
# This software is provided "as-is".  There are no expressed or implied
# warranties of any kind, including, but not limited to, the warranties
# of merchantability and fittness for a given application.  In no event
# shall Travis Vachonn be liable for any direct, indirect, incidental,
# special, exemplary or consequential damages (including, but not limited
# to, loss of use, data or profits, or business interruption) however
# caused and on any theory of liability, whether in contract, strict
# liability or tort (including negligence or otherwise) arising in any way
# out of the use of this software, even if advised of the possibility of
# such damage.
#

import SimpleXMLRPCServer
import time
from conf import *
import globals
import threading
import xen.lowlevel.xc as xc
import xen.lowlevel.xs as xs
from xen.xend.XendClient import server as xen_server
import os, sys
import os.path
import xenbal
# Get a xen_client object and set up some helper functions
xen_client = xc.xc()
xen_store = xs.xs()


# We'll now set up an XMLRPC server

class XenXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer,threading.Thread):
    def __init__(self,addr):
        threading.Thread.__init__(self)
        self.allow_reuse_address = True

        SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self,addr)
        self.allow_none = True
        self.migrating = False
 
    def run(self):
        self.serve_forever()
    
    def serve_forever(self):
        self.stop = False
        while not self.stop:
            self.handle_request()
        print "stopping server"
        return

    def server_close(self):
        globals.stop_updaters()
        self.stop = True

    def prepare_migrate(self):
        if self.migrating:
            return False
        else:
            self.migrating = True
            return True

    def finish_migrate(self):
        if self.migrating:
            self.migrating = False
            return True
        else:
            return False

    def _threaded_migrate(self,dom,dst,live=0,resource=0):
        try:
            xenbal.logger.debug("migration thread starting migrate " + str(dom) + " to " + dst)
            try:
                xenbal.logger.info("MIGRATION FINISHED WITH " + str(xen_server.xend_domain_migrate(dom,dst,live,resource)))
            except:
                xenbal.logger.warning("Migration failed!")
            xenbal.logger.debug("migration thread finished migrate")
            globals.peer_nodes[dst].server.finish_migrate()
        except:
            xenbal.logger.warning("Failed to migrate domain %s to %s." % str(dom), str(dst))
            globals.peer_nodes[dst].server.finish_migrate()
            

    def migrate(self,dom,dst,live,resource):
        if(globals.peer_nodes[dst].server.prepare_migrate()):
            xenbal.logger.info("no migration happening, migrating")
            xenbal.logger.debug("starting server migration thread")
            threading.Thread(target=self._threaded_migrate,args=(dom,dst,live,resource)).start()
            xenbal.logger.debug("server migration thread started")
            return True
        else:
            xenbal.logger.info("migration already in progress, not migrating")

            return False






xmlrpc_server = XenXMLRPCServer(('',XENBAL_PORT))

#------- XMLRPC functions -------
def test():
    return 1

def get_load(period):

    start_domain_cpu_time_dict = {}
    elapsed_domain_cpu_time_dict = {}
    
    for domain in xen_client.domain_getinfo():
        start_domain_cpu_time_dict[str(domain['dom'])] = domain['cpu_time']

    time.sleep(period)

    for domain in xen_client.domain_getinfo():
        elapsed_domain_cpu_time_dict[str(domain['dom'])] = domain['cpu_time'] -start_domain_cpu_time_dict[str(domain['dom'])]

    return elapsed_domain_cpu_time_dict



def exit():

    xmlrpc_server.server_close()
    return True


def get_domain_info():
    try:
        domain_info = xen_client.domain_getinfo()
        return_dict = {}
        xen_store_handle = xen_store.transaction_start()
        for domain in domain_info:
            name = xen_store.read(xen_store_handle,os.path.join(xen_store.get_domain_path(domain['dom']),'name'))
            if name == None:
                name = "No name"
            domain['name'] = name
            domain['cpu_time'] = str(domain['cpu_time'])
        
            #We must have strings as dictionary keys for xmlrpc
            return_dict[str(domain['dom'])] = domain

        xen_store.transaction_end(xen_store_handle)

    except:
        xenbal.logger.warning("Error in get_domain_info: " + sys.exc_traceback)
        return {}
    #xenbal.logger.debug("XMLRPC returning " + str(return_dict))
    return return_dict

xmlrpc_server.register_function(xmlrpc_server.migrate)
xmlrpc_server.register_function(xmlrpc_server.prepare_migrate)
xmlrpc_server.register_function(xmlrpc_server.finish_migrate)
xmlrpc_server.register_function(test)
xmlrpc_server.register_function(exit)
xmlrpc_server.register_function(get_domain_info)
xmlrpc_server.register_function(get_load)
xmlrpc_server.register_function(xen_client.physinfo)

#----------- Now set up balancer

balancer = xenbal.LoadBalancer(xenbal.NO_BAL_POLICY)




def stop_balancer():
    balancer.exit()
    return True


xmlrpc_server.register_function(stop_balancer)

xmlrpc_server.register_function(balancer.set_no_bal_policy)
xmlrpc_server.register_function(balancer.set_simplesi_policy)
xmlrpc_server.register_function(balancer.set_simpleri_policy)
xmlrpc_server.register_function(balancer.set_utilitysi_policy)
xmlrpc_server.register_function(balancer.set_utilityri_policy)




def start_threads():
    xmlrpc_server.start()
    print "XMLRPC server started"
    balancer.start()
    print "balancer started"
    globals.create_updaters()

    print "Updaters created"
